#!/usr/bin/env python
#-*- encoding:utf-8 -*-
#
#       Update Notifier (core part)
#
#       Kévin Gomez <geek63@gmail.com>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

from subprocess import Popen, PIPE
from os.path import isfile
import re


def run_async(func):
    """
        run_async(func)
            function decorator, intended to make "func" run in a separate
            thread (asynchronously).
            Returns the created Thread object

            E.g.:
            @run_async
            def task1():
                do_something

            @run_async
            def task2():
                do_something_too

            t1 = task1()
            t2 = task2()
            ...
            t1.join()
            t2.join()
    """
    from threading import Thread
    from functools import wraps

    @wraps(func)
    def async_func(*args, **kwargs):
        func_hl = Thread(target = func, args = args, kwargs = kwargs)
        func_hl.start()
        return func_hl

    return async_func


class Checker:

    @staticmethod
    def isDBLocked():
        return isfile('/var/lib/pacman/db.lck')

    @staticmethod
    def updateDB():
        if Checker.isDBLocked():
            return

        act = Popen(['sudo', 'pacman', '-Sy'], stdout=PIPE)

        while act.poll() is None:
            continue

        return True

    @staticmethod
    def checkForUpdates(callback):

        @run_async
        def do(callback):
            if Checker.isDBLocked():
                callback(0, [])

            Checker.updateDB()

            act = Popen(['pacman', '-Qu'], stdout=PIPE)

            while act.poll() is None:
                continue

            response = act.communicate()[0]
            nb_updates = Checker._getUpdatesCount(response)

            callback(nb_updates, [] if not nb_updates else \
                                Checker._getUpdatesList(response),
                    Checker._getDownloadSize(response))

        do(callback)

    @staticmethod
    def _getUpdatesCount(content):
        try:
            return int(re.findall(r'\((\d)\)', content)[0])
        except IndexError:
            return 0

    @staticmethod
    def _getUpdatesList(content):
        list = content.split(':', 1)[1].split('\n\n', 2)[0].split(' ')

        return [item for item in list if item.strip()]

    @staticmethod
    def _getDownloadSize(content):
        #TO FIX :: always equal to 0,00 Mo --> pacman bug ?
        list = [item for item in content.split('\n') if item.strip()][-2].split(' ')

        return '%s %s' % (list[-2], list[-1])